package com.woniu.cms.goods.core.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.woniu.cms.goods.core.entity.*;
import com.woniu.cms.goods.core.exception.Asserts;
import com.woniu.cms.goods.core.exception.BusinessException;
import com.woniu.cms.goods.core.mapper.GoodsSettleMapper;
import com.woniu.cms.goods.core.service.IGoodsOutbillMaterialService;
import com.woniu.cms.goods.core.service.IGoodsSettleMaterialService;
import com.woniu.cms.goods.core.service.IGoodsSettleService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.woniu.cms.goods.core.util.AspectsMsg;
import com.woniu.cms.goods.core.vo.SettleVo;
import com.woniu.common.api.Result;
import com.woniu.common.api.status.Impl.BusinessCode;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author romantic sheep
 * @since 2022-09-19
 */
@Service
public class GoodsSettleServiceImpl extends ServiceImpl<GoodsSettleMapper, GoodsSettle> implements IGoodsSettleService {

    @Autowired
    private IGoodsSettleMaterialService settleMaterialService;
    @Autowired
    private IGoodsOutbillMaterialService outbillMaterialService;


    @Override
    public Result getlist(Integer currentPage, Integer pageSize, Integer status) {
        LambdaQueryWrapper<GoodsSettle> qw = Wrappers.lambdaQuery();
        qw.eq(GoodsSettle::getStatus,status);
        IPage iPage=new Page(currentPage,pageSize);
        IPage page = this.page(iPage, qw);
        List<GoodsSettle> records = page.getRecords();
        List<SettleVo> collect = records.stream().map(e -> {
            SettleVo settleVo=new SettleVo();
            BeanUtils.copyProperties(e, settleVo);
            return settleVo;
        }).collect(Collectors.toList());
        long total = page.getTotal();
        Map map=new HashMap();
        map.put("data",collect);
        map.put("total",total);
        Result<Map> common = Result.common(map);
        return common;
    }

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result addSettle(GoodsSettle goodsSettle, List<GoodsSettleMaterial> list) {
        if (ObjectUtils.isEmpty(goodsSettle)){
            return Result.error("请输入必填数据");
        }
        //先保存结算单主表，保存失败抛出异常，事务回滚
        boolean save = this.save(goodsSettle);
        if (!save){
            Asserts.failed(AspectsMsg.SAVE_EXCEPTION);
        }
        //查询结算单单主表id，填入材料信息表外键
        LambdaQueryWrapper<GoodsSettle> qw = Wrappers.lambdaQuery();
        qw.eq(GoodsSettle::getSettleCode,goodsSettle.getSettleCode());
        GoodsSettle goodsSettle1 = this.getOne(qw);
        List<GoodsSettleMaterial> collect = list.stream().map(e -> {
            e.setSettleId(goodsSettle1.getId());
            return e;
        }).collect(Collectors.toList());
        //保存材料信息表。保存失败则事务回滚
        boolean b = settleMaterialService.saveBatch(collect);
        if (!b){
            Asserts.failed(AspectsMsg.SAVE_EXCEPTION);
        }
        return Result.ok(BusinessCode.ADD_SUCCESS);
    }

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result deleteSettle(Integer id, Integer status) {
        GoodsSettle goodsSettle = this.getById(id);
        if (ObjectUtils.isEmpty(goodsSettle)){
            return Result.error(BusinessCode.REMOVE_FAIL);
        }
        if (goodsSettle.getStatus()!=0&&goodsSettle.getStatus()!=3){
            return Result.error("单据已提交无法删除");
        }
        //先删除结算单单主表，删除失败则抛出异常，事务回滚。
        boolean b = this.removeById(id);
        if (!b){
            Asserts.failed(AspectsMsg.DELETE_EXCEPTION);
        }
        LambdaUpdateWrapper<GoodsSettleMaterial> updateWrapper = Wrappers.lambdaUpdate();
        updateWrapper.eq(GoodsSettleMaterial::getSettleId,id);
        //再删除结算单单材料明细表，删除失败则事务回滚
        boolean remove = settleMaterialService.remove(updateWrapper);
        if (!remove){
            Asserts.failed(AspectsMsg.DELETE_EXCEPTION);
        }
        return Result.ok(BusinessCode.REMOVE_SUCCESS);
    }

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result updateSettle(GoodsSettle goodsSettle, List<GoodsSettleMaterial> list) {
        if (goodsSettle.getStatus()!=0&&goodsSettle.getStatus()!=3){
            return Result.error(BusinessCode.MODIFY_FAIL);
        }
        //先修改结算单主表，修改失败则抛出异常事务回滚
        boolean b = this.updateById(goodsSettle);
        if (!b){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        //再修改结算单材料表，修改失败则抛出异常事务回滚
        boolean b1 = settleMaterialService.updateBatchById(list);
        if (!b1){
            Asserts.failed(AspectsMsg.UPDATE_EXCEPTION);
        }
        return Result.ok(BusinessCode.MODIFY_SUCCESS);
    }

    @Override
    @Transactional( propagation = Propagation.REQUIRED  //必须添加事务
            ,timeout = -1         //设置连接永不超时
            ,rollbackFor = {BusinessException.class}  // 抛出异常时进行回滚
            ,isolation = Isolation.DEFAULT                   // 使用数据库的隔离级别
    )
    public Result commitSettle(GoodsSettle goodsSettle, List<GoodsSettleMaterial> list) {
        if (goodsSettle.getStatus()==2){
            return Result.error("单据已提交，无法重复提交");
        }
        System.out.println("GoodsSettleServiceImpl.commitSettle");
        List<Integer> ids = list.stream().map(e -> e.getOutbillMaterialId()).collect(Collectors.toList());
        List<GoodsOutbillMaterial> outbillMaterials = outbillMaterialService.listByIds(ids);
        list.sort(new Comparator<GoodsSettleMaterial>() {
            @Override
            public int compare(GoodsSettleMaterial o1, GoodsSettleMaterial o2) {
                return o1.getOutbillMaterialId()-o2.getOutbillMaterialId();
            }
        });
        outbillMaterials.sort(new Comparator<GoodsOutbillMaterial>() {
            @Override
            public int compare(GoodsOutbillMaterial o1, GoodsOutbillMaterial o2) {
                return o1.getId()-o2.getId();
            }
        });
        for (int i=0;i<list.size();i++){
            BigDecimal settleNum = list.get(i).getSettleNum();
            BigDecimal realNum = outbillMaterials.get(i).getRealNum();
            if (settleNum.compareTo(realNum)==1){
                return Result.error("提交失败，材料库存不足");
            }else {
                BigDecimal subtract = realNum.subtract(settleNum);
                GoodsOutbillMaterial goodsOutbillMaterial = outbillMaterials.get(i);
                goodsOutbillMaterial.setRealNum(subtract);
            }
        }
        goodsSettle.setStatus(1);
        boolean b = this.updateById(goodsSettle);
        if (!b){
            Asserts.failed(AspectsMsg.COMMIT_EXCEPTION);
        }
        boolean b1 = settleMaterialService.updateBatchById(list);
        if (!b1){
            Asserts.failed(AspectsMsg.COMMIT_EXCEPTION);
        }
        boolean b2 = outbillMaterialService.updateBatchById(outbillMaterials);
        if (!b2){
            Asserts.failed(AspectsMsg.COMMIT_EXCEPTION);
        }
        return Result.ok("单据提交成功");
    }


}
